home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Cream of the Crop 21
/
Cream of the Crop 21 (Terry Blount) (October 1996).iso
/
program
/
libkb100.zip
/
LIBKB-1.00
/
SRC
/
KBMLOCK.C
< prev
next >
Wrap
C/C++ Source or Header
|
1996-07-23
|
11KB
|
512 lines
/* kbmlock.c -- memory locking
* Copyright (C) 1995, 1996 Markus F.X.J. Oberhumer
* For conditions of distribution and use, see copyright notice in kb.h
*/
/* memory locking is currently implemented for djgpp v2 and Watcom C32 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <kb.h>
#include <kbmlock.h>
#include "_kb.h"
/* see also: DPMI specification
* djgpp2/src/libc/go32/gopint.c
* djgpp2/src/libc/dpmi/api/d0600.s
*/
#if defined(KB_LOCK_ALL_START)
KB_LOCK_ALL_START(_libkb_kbmlock)
#endif
typedef struct
{
int selector;
unsigned long address;
long size;
unsigned long linear_address;
}
kb_lockaddr_t;
/***********************************************************************
// DPMI support for Watcom C32 (djgpp v2 compatible)
************************************************************************/
#if defined(__WATCOMC__) && defined(__KB_MSDOS32)
typedef struct
{
unsigned long handle; /* 0, 2 */
unsigned long size; /* or count */ /* 4, 6 */
unsigned long address; /* 8, 10 */
} __dpmi_meminfo;
/* it looks like every base address is 0 under DOS/4GW and PMODE/W */
/* DPMI 0.9 AX=0006 */
static
int __dpmi_get_segment_base_address(int _selector, unsigned long *_addr)
{
KB_INT86_REGS regs;
_kb_int86_regs_init_ax(®s,0x0006);
regs.w.bx = (unsigned short) _selector;
regs.w.flags = 0x01; /* be paranoid */
KB_INT86(0x31,®s);
if (regs.w.flags & 0x01) /* error if carry flag set */
return -1;
*_addr = ((unsigned long)regs.w.cx << 16) | regs.w.dx;
return 0;
}
static
int watcom_c32_do_lock(__dpmi_meminfo *_info, unsigned short ax)
{
KB_INT86_REGS regs;
_kb_int86_regs_init_ax(®s,ax);
regs.w.bx = (unsigned short) (_info->address >> 16);
regs.w.cx = (unsigned short) (_info->address);
regs.w.si = (unsigned short) (_info->size >> 16);
regs.w.di = (unsigned short) (_info->size);
regs.w.flags = 0x01; /* be paranoid */
KB_INT86(0x31,®s);
return (regs.w.flags & 0x01 ? -1 : 0); /* error if carry flag set */
}
/* DPMI 0.9 AX=0600 */
static
int __dpmi_lock_linear_region(__dpmi_meminfo *_info)
{
return watcom_c32_do_lock(_info,0x0600);
}
/* DPMI 0.9 AX=0601 */
static
int __dpmi_unlock_linear_region(__dpmi_meminfo *_info)
{
return watcom_c32_do_lock(_info,0x0601);
}
#endif /* __WATCOMC__ */
/***********************************************************************
// low level locking - djgpp v2, Watcom C32
************************************************************************/
#if defined(__KB_MSDOS32)
#if defined(__DJGPP__) || defined(__WATCOMC__)
#define KB_HAVE_LOCK
static int _kb_lock_lockaddr(const kb_lockaddr_t *l, int do_lock)
{
int r;
__dpmi_meminfo memregion;
memregion.handle = 0;
memregion.address = l->linear_address;
memregion.size = l->size;
if (l->size <= 0)
r = -1;
else if (do_lock)
r = __dpmi_lock_linear_region(&memregion);
else
r = __dpmi_unlock_linear_region(&memregion);
#if defined(KB_DEBUG) && (KB_DEBUG >= 3)
fprintf(stderr,"libkb lockinfo: %-6s %04x:%08lx (0x%08lx), "
"%6ld bytes: %d\n", do_lock ? "lock" : "unlock",
l->selector, l->address, l->linear_address, l->size, r);
#endif
return r;
}
static
int _kb_init_lockaddr(kb_lockaddr_t *l, int seg, unsigned long lockaddr,
long locksize, int code)
{
int r;
l->selector = seg;
#if defined(__DJGPP__)
if (l->selector == -1)
l->selector = code ? _go32_my_cs() : _go32_my_ds();
#endif
l->address = lockaddr;
l->size = locksize;
l->linear_address = 0;
r = __dpmi_get_segment_base_address(l->selector,&l->linear_address);
if (r == 0)
l->linear_address += l->address;
else
l->linear_address = 0;
#if defined(KB_DEBUG) && (KB_DEBUG >= 4)
fprintf(stderr,"libkb lockinfo: %-6s %04x:%08lx (0x%08lx), "
"%6ld bytes\n", "", l->selector, l->address,
l->linear_address, l->size);
#endif
if (r != 0)
l->size = -1;
return l->size > 0 ? 0 : -1;
}
#if defined(__DJGPP__)
# define KB_INIT_LOCKADDR(l,addr,size,code) \
_kb_init_lockaddr(l,-1,(unsigned long)(addr),size,code)
#elif defined(__WATCOMC__)
# define KB_INIT_LOCKADDR(l,addr,size,code) \
_kb_init_lockaddr(l,FP_SEG(addr),FP_OFF(addr),size,code)
#endif
#endif
#endif /* __KB_MSDOS32 */
/***********************************************************************
// init a kb_lockaddr_t
************************************************************************/
static
int _kb_init_lock_code(kb_lockaddr_t *l, void (*start)(void), void (*end)(void))
{
l->size = -1;
if (start == NULL || end == NULL || start == end)
return -1;
#if defined(KB_INIT_LOCKADDR)
/* warning: ANSI C forbids ordered comparisons of pointers to functions */
{
unsigned long s = (unsigned long) start;
unsigned long e = (unsigned long) end;
if (e > s)
return KB_INIT_LOCKADDR(l,start,e-s,1);
else if (s > e)
return KB_INIT_LOCKADDR(l,end,s-e,1);
else
return -1;
}
#else
l->size = 0;
return 0;
#endif
}
static
int _kb_init_lock_data(kb_lockaddr_t *l, const void *start, const void *end)
{
l->size = -1;
if (start == NULL || end == NULL || start == end)
return -1;
#if defined(KB_INIT_LOCKADDR)
if (end > start)
return KB_INIT_LOCKADDR(l,start,(const char*)end-(const char*)start,0);
else if (start > end)
return KB_INIT_LOCKADDR(l,end,(const char*)start-(const char*)end,0);
else
return -1;
#else
l->size = 0;
return 0;
#endif
}
/***********************************************************************
// high level locking
************************************************************************/
int kb_lock_code(void (*start)(void), void (*end)(void))
{
kb_lockaddr_t l;
if (_kb_init_lock_code(&l,start,end) != 0)
return -1;
#if defined(KB_HAVE_LOCK)
return _kb_lock_lockaddr(&l,1);
#else
return 0;
#endif
}
int kb_lock_data(const void *start, const void *end)
{
kb_lockaddr_t l;
if (_kb_init_lock_data(&l,start,end) != 0)
return -1;
#if defined(KB_HAVE_LOCK)
return _kb_lock_lockaddr(&l,1);
#else
return 0;
#endif
}
int kb_lock_var(const void *addr, unsigned size)
{
return kb_lock_data(addr,(const char *)addr + size);
}
/***********************************************************************
// high level unlocking
************************************************************************/
int kb_unlock_code(void (*start)(void), void (*end)(void))
{
kb_lockaddr_t l;
if (_kb_init_lock_code(&l,start,end) != 0)
return -1;
#if defined(KB_HAVE_LOCK)
return _kb_lock_lockaddr(&l,0);
#else
return 0;
#endif
}
int kb_unlock_data(const void *start, const void *end)
{
kb_lockaddr_t l;
if (_kb_init_lock_data(&l,start,end) != 0)
return -1;
#if defined(KB_HAVE_LOCK)
return _kb_lock_lockaddr(&l,0);
#else
return 0;
#endif
}
int kb_unlock_var(const void *addr, unsigned size)
{
return kb_unlock_data(addr,(const char *)addr + size);
}
/***********************************************************************
// merge overlapping regions
//
// We try to lock as few different regions as possible.
************************************************************************/
#if defined(KB_HAVE_LOCK)
static int _kb_merge2(kb_lockaddr_t *l1, kb_lockaddr_t *l2)
{
unsigned long end1, end2;
if (l1->size <= 0 || l2->size <= 0)
return 0;
end1 = l1->linear_address + l1->size;
end2 = l2->linear_address + l2->size;
/* try to merge l2 into l1 */
if (l1->linear_address <= l2->linear_address &&
end1 + 1 >= l2->linear_address)
{
if (end2 > end1)
l1->size = end2 - l1->linear_address;
l2->size = 0;
return 1;
}
/* try to merge l1 into l2 */
if (l2->linear_address <= l1->linear_address &&
end2 + 1 >= l1->linear_address)
{
if (end1 > end2)
l2->size = end1 - l2->linear_address;
l1->size = 0;
return 1;
}
return 0;
}
static
int _kb_merge_lockaddr(kb_lockaddr_t l[], int n)
{
int i, j;
int found;
/* a simple 'bubblemerge' (like bubblesort) */
do {
found = 0;
for (i = 0; i < n - 1; i++)
for (j = i + 1; j < n; j++)
if (_kb_merge2(&l[i],&l[j]))
found = 1;
} while (found);
return 0;
}
#if defined(KB_DEBUG) && (KB_DEBUG >= 4)
static
void _kb_print_lockaddr(const kb_lockaddr_t ll[], int n, const char *s)
{